# See for codes
# http://www.djangoproject.com/documentation/models/test_client/
from datetime import datetime, timedelta
from django.core.files.base import ContentFile
from django.test import TestCase, Client
from django.contrib.auth.models import User
from django.utils.http import urlquote

from pypsqueak.page.models import *
from pypsqueak.artifact.models import Artifact
from pypsqueak.chrome.forms import ChromeModelForm

class PageModelTestCase(TestCase):
	"""
	Test Models
	"""


	def setUp(self):
		u = User( username = "Bob" )
		u.save()

# MonkeyPatch Test

	def testMonkeyPatchUserChildren(self):
		""" Make sure that the user.children() function works. """

		u = User.objects.filter(username="Bob")[0]

		p = Page( user=u, title="Bob" )
		p.save()

		self.assertEquals(len(u.getChildren() ), 1)

# Slug Testing

	def testUserSlugDuplication(self):
		""" Make sure each user's page has a unique slugs """

		uTim = User( username = "Tim" )
		uTim.save()
		p1 = Page( user=uTim, title="Homepage" )
		p1.save()

		# Ensure user slugs are unique for a single user (not all users)
		uBob = User.objects.filter(username="Bob")[0]
		p2 = Page( user=uBob, title="Homepage" )
		p2.save()

		# Ensure the Homepage1 is the new slug, since homepage already exists
		p3 = Page( user=uBob, title="Homepage" )
		p3.save()

		self.assertEquals( p2.slug, "Homepage" );
		self.assertEquals( p3.slug, "Homepage_1" );

		p1.delete()
		p2.delete()
		p3.delete()
		uTim.delete()


	def testUserSlugMaxLength(self):
		""" Make sure slugs are automatically shortened properly """

		u = User.objects.filter(username="Bob")[0]
		max_len = Page._meta.get_field_by_name('slug')[0].max_length

		title = "".ljust( max_len+1, "X" )

		# Test normal shorting (simple truncation)
		p = Page( user=u, title=title )
		p.save()
		self.assertEquals( p.slug, title[:-1] )
		p.delete()


	def testUserSlugMaxLengthSpecialCharacters(self):
		""" Make sure URL-expanded slugs special characters are shortened properly """

		u = User.objects.filter(username="Bob")[0]
		max_len = Page._meta.get_field_by_name('slug')[0].max_length

		title = "".ljust( max_len+10, "#" )

		# Test normal shorting (simple truncation)
		p = Page( user=u, title=title )
		p.save()
		self.assertEquals( len(p.slug) <= max_len, True )
		p.delete()


	def testUserSlug24HourReset(self):
		""" Make sure slugs are changed up to 24 hours after page creation """

		u = User.objects.filter(username="Bob")[0]
		title = "TimeTest"

		# Test normal shorting (simple truncation)
		p = Page( user=u, title= title )
		p.created = datetime.now() + timedelta( days=-2 )
		p.save()

		# Slug is set now.  Change title
		p.title = "Test2"
		p.save()

		# Too old to change.
		self.assertEquals( p.slug, title )

		# <24 hours old, should change slug on save.
		p.created = datetime.now() + timedelta( hours=-23 )
		p.save()

		self.assertNotEquals( p.slug, title )

		#Cleanup
		p.delete()


	def testUserSlugSpecialCharacters(self):
		""" Make sure URL-expanded slugs special characters are unique """

		u = User.objects.filter(username="Bob")[0]
		max_len = Page._meta.get_field_by_name('slug')[0].max_length

		title = "".ljust( max_len+10, "'" )

		title = "!@#$%@#@#$"

		# Test normal shorting (simple truncation)
		p = Page( user=u, title= title )
		p.save()
		self.assertEquals( len(p.slug) <= max_len, True )

		p2 = Page( user=u, title= title )
		p2.save()
		self.assertNotEquals( p.slug , p2.slug )

		p3 = Page( user=u, title= title )
		p3.save()
		self.assertNotEquals( p.slug , p2.slug )
		self.assertNotEquals( p.slug , p3.slug )
		self.assertNotEquals( p2.slug , p3.slug )

		p.delete()
		p2.delete()
		p3.delete()


	def testUserSlugDuplicationSpecialCharacters(self):
		""" Make sure URL-expanded slugs shorted w/o duplicates """

		u = User.objects.filter(username="Bob")[0]
		max_len = Page._meta.get_field_by_name('slug')[0].max_length

		title = "".ljust( max_len, "#" )

		# Test normal shorting (simple truncation)
		p1 = Page( user=u, title=title )
		p1.save()
		p2 = Page( user=u, title=title )
		p2.save()
		self.assertNotEquals( p1.slug, p2.slug )
		p1.delete()
		p2.delete()



	def tearDown(self):
		u = User.objects.filter(username="Bob")[0]
		u.delete()



class PageViewsTestCase(TestCase):
	""" Test Views for Pages """

	def setUp(self):

		# Create test users.
		self.owner_user = User(
			username = 'owner',
			last_name='last_name',
			first_name='first_name'
			)
		self.owner_user.set_password( 'password' )
		self.owner_user.save()

		self.other_user = User(
			username = 'other',
			last_name='last_name',
			first_name='first_name',
			)
		self.other_user.set_password( 'password' )
		self.other_user.save()


		# Create test page
		self.page = Page()
		self.page.title = 'Title'
		self.page.body = 'Body'
		self.page.user = self.owner_user
		self.page.save()


	def testPage_AnonUserFailure(self):
		""" Test Anonymous user rights to access/edit a page """

		c = Client()
		self.view(c,False)


	def testPage_NotOwnerUserFailure(self):
		""" Test a normal user right's to access/edit a page they don't own. """

		c = Client()
		response = c.login(username=self.other_user.username, password='password')
		self.assertEquals( response, True)

		self.view(c,False)

	def testPage_OwnerSuccess(self):
		""" Test owner's rights to a page they own. """
		c = Client()
		response = c.login(username=self.owner_user.username, password='password')
		self.assertEquals( response, True)

		self.view(c,True)


	def view(self, client, result):
		# Expected results

		if result:
			equal = self.assertEqual
			contains = self.assertContains
		else:
			equal = self.assertNotEqual
			contains = self.assertNotContains


		# Does the homepage have an 'add' field?
		response = client.get( self.owner_user.get_absolute_url() )
		contains( response, Page.get_insert_url(self.owner_user))

		# Make sure that the insert view throws http error
		#response = client.get( self.group.get_insert_url() )
		#equal( response.status_code, 200 )
		#if response.status_code == 200:
		#	contains(response, ChromeModelForm.insert)

		# Test detail view to ensure links are/aren't shown.
		#response = client.get(self.group.get_absolute_url() )
		#contains(response, self.group.get_update_url())
		#contains(response, self.group.get_delete_url())

		# Test update view throwing http error or redirect
		#response = client.get( self.group.get_update_url() )
		#equal( response.status_code, 200 )
		#if response.status_code == 200:
		#	contains(response, ChromeModelForm.update )

		# Test delete view throwing http error or redirect
		#response = client.get( self.group.get_delete_url() )
		#equal( response.status_code, 200 )
		#if response.status_code == 200:
		#	contains(response, ChromeModelForm.delete )


	def tearDown(self):
		self.page.delete()
		self.other_user.delete()
		self.owner_user.delete()





class PageArtifactModelFileUploadTestCase(TestCase):
	"""
	Test Models
	"""

	def setUp(self):
		u = User( username = "Bob" )
		u.save()


	def testFileInMemory(self):
		""" Upload a file for an artifact """

		u = User.objects.filter(username="Bob")[0]

		p = Page( user=u, title="Home" )
		p.save()

		f = ContentFile( 'Default Content' )
		a = Artifact(file=f)
		a.save()

		pa = PageArtifact( artifact=a, page=p )
		pa.save()

		self.assertEquals( True, True )

		p.delete()


	def tearDown(self):
		u = User.objects.filter(username="Bob")[0]
		u.delete()




class PageArtifactViewAndFormTestCase(TestCase):
	""" Test form for artifacts. """

	def setUp(self):

		# Create test users.
		self.owner_user = User(
			username = 'staff',
			last_name='last_name',
			first_name='first_name',
			is_staff=True
			)
		self.owner_user.set_password( 'password' )
		self.owner_user.save()

		self.other_user = User(
			username = 'other',
			last_name='last_name',
			first_name='first_name',
			)
		self.other_user.set_password( 'password' )
		self.other_user.save()

		# Create test page.
		self.page = Page()
		self.page.title = 'Page'
		self.page.user = self.owner_user
		self.page.save()

		# Create test artifact.
		f = ContentFile( 'Default Content' )
		a = Artifact(file=f)
		a.save()

		self.pageartifact = PageArtifact()
		self.pageartifact.page = self.page
		self.pageartifact.artifact = a



	def testGroup_AnonUserFailure(self):
		""" Test Anonymous user group rights. """

		c = Client()
		self.view(c,False)


	def testGroup_OtherUserFailure(self):
		""" Test non-owner user group rights. """

		c = Client()
		response = c.login(username=self.other_user.username, password='password')
		self.assertEquals( response, True)
		self.view(c,False)

	def testGroup_OwnerSuccess(self):
		""" Test owner user's rights. """
		c = Client()
		response = c.login(username=self.owner_user.username, password='password')
		self.assertEquals( response, True)

		self.view(c,True)


	def view(self, client, result):
		# Expected results

		if result:
			equal = self.assertEqual
			contains = self.assertContains
		else:
			equal = self.assertNotEqual
			contains = self.assertNotContains


		# Make sure that the insert view throws http error
		response = client.get( PageArtifact.get_insert_url(self.page) )
		equal( response.status_code, 200 )
		if response.status_code == 200:
			contains(response, ChromeModelForm.insert )

		return True

		# Test detail view to ensure links are/aren't shown.
		response = client.get(self.artifact.get_absolute_url() )
		contains(response, self.artifact.get_update_url())
		contains(response, self.artifact.get_delete_url())

		# Test update view throwing http error or redirect
		response = client.get( self.artifact.get_update_url() )
		equal( response.status_code, 200 )
		if response.status_code == 200:
			contains(response, ChromeModelForm.update )

		# Test delete view throwing http error or redirect
		response = client.get( self.artifact.get_delete_url() )
		equal( response.status_code, 200 )
		if response.status_code == 200:
			contains(response, ChromeModelForm.delete )


	def tearDown(self):
		self.page.delete()
		self.other_user.delete()
		self.owner_user.delete()
